﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;
using System.Globalization;
using System.IO;

namespace SilverlightPlayground.RFB
{
    public class RfbMediaStreamSource : MediaStreamSource
    {
        private int FrameWidth { get; set; }
        private int FrameHeight { get; set; }
        private MediaStreamDescription Description { get; set; }
        private RfbClient Client { get; set; }
        private Queue<byte[]> Buffers { get; set; }

        public RfbMediaStreamSource(string host, int port)
        {
            this.Buffers = new Queue<byte[]>();
            this.Client = new RfbClient(host, port);
            this.Client.ResizeFrameBuffer += new EventHandler(Client_ResizeFrameBuffer);
        }

        /// <summary>
        /// Handles the ResizeFrameBuffer event of the Client control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void Client_ResizeFrameBuffer(object sender, EventArgs e)
        {
            this.FrameWidth = this.Client.CurrentFrameBufferWidth;
            this.FrameHeight = this.Client.CurrentFrameBufferHeight;

            this.Buffers.Clear();
            this.Buffers.Enqueue(new byte[this.FrameWidth * this.FrameHeight * this.Client.BytesPerPlane]);
            this.Buffers.Enqueue(new byte[this.FrameWidth * this.FrameHeight * this.Client.BytesPerPlane]);
        }

        protected override void CloseMedia()
        { }

        protected override void GetDiagnosticAsync(MediaStreamSourceDiagnosticKind diagnosticKind)
        { }

        protected override void GetSampleAsync(MediaStreamType mediaStreamType)
        {
            // seems like creating a new stream is only way to avoid out of memory and
            // actually figure out the correct offset. that can't be right.
            using (MemoryStream frameStream = new MemoryStream())
            {
//                _frameStream.Write(_frames[_currentReadyFrame], 0, _frameBufferSize);

                //// Send out the next sample
                //MediaStreamSample msSamp = new MediaStreamSample(
                //    _videoDesc,
                //    _frameStream,
                //    0,
                //    _frameBufferSize,
                //    _currentVideoTimeStamp,
                //    _emptySampleDict);

                //_currentVideoTimeStamp += _frameTime;

                //ReportGetSampleCompleted(msSamp);
            }
        }

        protected override void OpenMediaAsync()
        {
            // Init
            Dictionary<MediaSourceAttributesKeys, string> sourceAttributes =
                new Dictionary<MediaSourceAttributesKeys, string>();
            List<MediaStreamDescription> availableStreams =
                new List<MediaStreamDescription>();

            PrepareVideo();

            availableStreams.Add(this.Description);

            // a zero timespan is an infinite video
            sourceAttributes[MediaSourceAttributesKeys.Duration] =
                TimeSpan.FromSeconds(0).Ticks.ToString(CultureInfo.InvariantCulture);

            sourceAttributes[MediaSourceAttributesKeys.CanSeek] = false.ToString();

            // tell Silverlight that we've prepared and opened our video
            this.ReportOpenMediaCompleted(sourceAttributes, availableStreams);
        }

        protected override void SeekAsync(long seekToTime)
        { }

        protected override void SwitchMediaStreamAsync(MediaStreamDescription mediaStreamDescription)
        { }

        private void PrepareVideo()
        {
            // Stream Description 
            Dictionary<MediaStreamAttributeKeys, string> streamAttributes =
                new Dictionary<MediaStreamAttributeKeys, string>();

            streamAttributes[MediaStreamAttributeKeys.VideoFourCC] = "RGBA";
            streamAttributes[MediaStreamAttributeKeys.Height] = this.FrameHeight.ToString();
            streamAttributes[MediaStreamAttributeKeys.Width] = this.FrameWidth.ToString();

            MediaStreamDescription msd =
                new MediaStreamDescription(MediaStreamType.Video, streamAttributes);

            this.Description = msd;

//            this.Client.Connect();
        }
    }
}